[spark-compete wave 5] security cross-cut (stacked) - #885
Merged
Conversation
Pin devalue to >=5.8.1 via package.json `overrides` to remediate a DoS-via-sparse-array advisory. Regenerated package-lock.json so the resolved devalue version moves 5.7.1 -> 5.8.1. Narrowed from the original PR per maintainer review: the unrelated `vitest ^4.0.16 -> ^4.1.0` devDependency bump was scope creep against the security claim and was dropped. Co-authored-by: ifeoluwaaj <ifeoluwaaj@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Consolidates a same-author path-redaction series: - Remove tracePath from creator mission GET response (#877) - Remove server path from mission active POST response (#876) - Remove rawResponse field from analyze error response (#874) - Remove x-spark-preview-root header leaking server path (#873) - Use trusted x-real-ip / last x-forwarded-for entry for the rate-limiter client key (#875) Surviving-line indentation normalized back to file style (the patches bundled an over-indentation reflow of untouched lines). Co-authored-by: Esc1200 <Esc1200@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Validate targetFolder in PRD bridge write stays within the workspace root before writing, rejecting traversal outside cwd (#862) - Validate workingDirectory in the dispatch endpoint against the Spark workspace root so spawned processes cannot run with an arbitrary cwd (#861) - Reject interpreter code-execution flags in creator-mission validation commands, and validate missionId format against path traversal (#869). Completed the flag denylist per review: added node -p/--print and python -m/--module alongside the original -c/--command/-e/--eval/-. #860 (teams endpoint auth) is already satisfied by a superior requireTeamsAuth implementation on the base branch — no change landed. harness_core interim_until_migration for the creator-mission validation path: re-home into Governor on migration. Co-authored-by: ifeoluwaaj <ifeoluwaaj@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Independent single-file hardening fixes: - scheduler: in-flight Set so _tick cannot relaunch a record whose previous fire is still running (#858) - command-runner: SIGKILL escalation timer at timeoutMs+5s, cleared on close and error, so a SIGTERM-ignoring child can't hang the caller (#855) - retry-after: cap honoured Retry-After at 60s so a hostile/quota-exhausted upstream can't stall a mission for hours (#853) - sync-client: cap reconnect backoff at 30s and add +/-25% jitter so a fleet of tabs doesn't reconnect in lockstep (#824) - spark-harness-client: tolerate up to 3 transient status-poll failures before failing the mission (#823) - events POST: dedup caller-supplied event ids within a 5m window so a retried POST doesn't fan out duplicate events (#851) - brief-enricher: validate positive-numeric env overrides (#852) - h70-skill-matcher: precompute multi-word phrase keys once at module load instead of per task (#872) - canvas store: mirror sibling-tab writes via storage events, skipping while local edits are pending (#859) - MissionBoard: guard NaN dates in relative-time formatting (#842) harness_core interim_until_migration for scheduler: re-home into Governor on migration. Co-authored-by: 4gjnbzb4zf-sudo <4gjnbzb4zf-sudo@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…visibility mission-control-relay.ts: - Cap missionLifecycleStates / taskLifecycleStates at 5000 entries with oldest-insertion eviction so the process-lifetime maps can't grow unbounded (#854) - Seed the dedup maps from persisted recent entries at module load so a restart doesn't re-broadcast already-recorded terminal lifecycle events to Spark ingest and webhooks (#827). Seeding routes through the bounded insertion path to preserve the cap invariant. - Export isMissionControlMissionId and warn (only when a missionId is present) when a mission event is accepted but dropped from the board because its missionId doesn't match the required shape (#69) events POST: surface boardEligible in the response so callers learn at emit time that their event won't appear on the board (#69). #854 and #827 overlap on the same maps via different mechanisms (cap vs restart-seed) and compose cleanly; both land. Co-authored-by: 4gjnbzb4zf-sudo <4gjnbzb4zf-sudo@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d relays - mission-executor: after a debounced state-sync POST resolves, re-check the live status and DELETE the active-mission record if the mission is now terminal, so a cancel/complete that landed during the in-flight POST isn't clobbered back to "running" and resumed (#856). Adjusted per review: the new DELETE now passes getEventsAuthHeaders() to match the sync POST and clearFileSyncState DELETE in this file, so an auth-enforcing endpoint actually clears the stale record. - prd-bridge/load-to-canvas: guard the lifecycle relays with an alreadyLoaded check (pendingRequestMeta.status === 'canvas_loaded') so a retried POST doesn't re-fire mission_created/task_completed to operators or seed the relay history twice (#850). Resolved the merge conflict against the base's added task_completed relay by guarding both relays; pendingRequestMeta is loaded fresh from the persisted file each request, so a retry sees the prior request's canvas_loaded status. harness_core interim_until_migration for #856: re-home into Governor on migration. Co-authored-by: 4gjnbzb4zf-sudo <4gjnbzb4zf-sudo@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e/ID sites Same-author entropy-hardening series, reduced to the disclosed security lines per review (all undisclosed UX/gitignore/test hunks stripped — most were already independently landed on the base branch): - creator-mission saveCreatorMissionTrace: atomic-write temp path no longer embeds process.pid+Date.now() (predictable -> symlink pre-emption); use randomUUID() with the codebase's node:crypto import convention (#825) - provider-runtime persist: same predictable temp-path fix, randomUUID() via node:crypto import (#826) - canvas store: the 4 connection-ID sites switch from Math.random().toString(36) to crypto.randomUUID() Web Crypto global (#867) Per review notes: took ONLY the security lines, used the node:crypto randomUUID import (not a bare crypto. global) in the server files, and discarded the tautological re-implementation tests. Co-authored-by: TALLSOME24 <TALLSOME24@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Surface diagnostics from catch blocks that swallowed errors silently: - access-execution-actions: spark binary lookup failure - command-runner: dependency check + package.json parse failures - spawner-state: file-scan entry + helper-text read failures Resurrected from closed PR #109 and adjusted per review: re-indented the added lines to tabs to match the file style (the PR introduced space-indented catch blocks), and dropped the agent-event-ledger hunks because the base already logs those two JSONL-parse failures via warnMalformedJsonlLine. The logged error objects are binary-lookup / JSON-parse / file-IO errors only — no request bodies, credentials, or env secrets are surfaced. Co-authored-by: johncrossu <johncrossu@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… compares Pad both buffers to the longer length before timingSafeEqual so the length comparison no longer short-circuits and leaks a timing side-channel. The exact-length equality is still required for a true result, but it is now evaluated only after the constant-time compare. Applied to both hosted-ui-auth and mcp-auth constantTimeEquals. Co-authored-by: ifeoluwaaj <ifeoluwaaj@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…flection)
The event bridge reflected any incoming Origin into
Access-Control-Allow-Origin, allowing any site to make credentialed
cross-origin requests. Gate corsHeaders behind an allowlist: loopback
dev origins are always permitted (matching mcp-auth's isOriginAllowed),
and any other origin must be explicitly listed in EVENTS_ALLOWED_ORIGINS.
The env var is resolved with the same process.env-then-dynamic-env
convention used by allowedOriginsEnvVar('EVENTS_ALLOWED_ORIGINS')
elsewhere, so configuration stays uniform across the control surfaces.
Per maintainer review, the redundant teams GET auth hunk from the
original PR is dropped — HEAD already authenticates teams GET via
requireTeamsAuth/requireControlAuth — so only the events corsHeaders
allowlist lands here.
Co-authored-by: yossweh <yossweh@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…not cwd; un-block python -m The wave5 hardening over-reached in two places and broke legitimate runs: - creator-mission validation rejected python -m <module>. `-m` runs a named, importable module on disk (e.g. `python -m pytest tests`) and never evaluates an inline code string, so it does not belong in the inline-eval denylist. It is the default manifest validation command and the planner's own invocation form. Removed -m/--module from DANGEROUS_INTERPRETER_FLAGS; -c/--command/-e/--eval/-p/--print/- still rejected. - PRD-bridge write validated the extracted target folder against process.cwd() (the SvelteKit app root). The spawner writes generated projects and static proofs under its own state/workspace tree, so legitimate targets were rejected. Now checks containment against the configured Spark workspace root and the spawner state dir using the project's isWithinDirectory helper, honors SPARK_ALLOW_EXTERNAL_PROJECT_PATHS, canonicalizes through symlinks (stable /var vs /private/var), and preserves explicit foreign-OS absolute targets (a user's C:\... build folder) verbatim. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- events.auth: the events route now also imports isMissionControlMissionId from mission-control-relay (board-eligibility flag). The vi.mock only exported relayMissionControlEvent, so the new call threw and every terminal-lifecycle assertion 400'd. Add a faithful isMissionControlMissionId to the mock. - hosted-ui-auth: the rate-limit client key was hardened to trust the last x-forwarded-for hop (set by our proxy) instead of the spoofable leftmost entry. Assert the trusted hop (10.0.0.1) is used. - creator-mission integration: the GET response intentionally no longer leaks the absolute server tracePath (#877 path-redaction series). Assert tracePath is undefined on GET (POST still returns it and is unchanged). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
vibeforge1111
changed the base branch from
spark-compete/wave3-builder-mission
to
main
June 26, 2026 13:18
vibeforge1111
marked this pull request as ready for review
June 26, 2026 13:20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Spark Compete — Wave 5 (security cross-cut), stacked on
spark-compete/wave3-builder-missionHighest-value security set. Wave-5 delta only.
Commits
On-merge points
ifeoluwaaj 30 · yossweh 16
Verified: proportionate diff, no churn, no conflict markers. Compiles / tests green. Draft — gated on CI + approval.
🤖 Generated with Claude Code